package com.zyy.jomap.back;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.zyy.jomap.JoMapProcessor;
import com.zyy.jomap.constant.Constant;
import com.zyy.jomap.back.definition.ClazzDefinition;
import com.zyy.jomap.back.definition.MethodDefinition;
import com.zyy.jomap.util.StringUtil;

import javax.tools.JavaFileObject;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * OK
 *
 * 生成JAVA文件处理类
 */
public class ResolveJavaFile {

    public static String TAB="    ";

    public static void main(String[] args) {
        String filePath="f:/workspace/jomap/src/main/java/com/zyy/jomap/JoMap.java";
        JavaParser javaParser = new JavaParser();
        try {
            ParseResult result= javaParser.parse(new File(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void build(){
        ClazzDefinition clazzDefinition=new ClazzDefinition();
        clazzDefinition.setClazzName("ProjectConvert");
        Set<String> importSet=new HashSet<>();
        importSet.add("com.zyy.process.bo.EntityBO");
        List<MethodDefinition> methodList=new ArrayList<>();
        MethodDefinition methodDefinition=new MethodDefinition();
        //此时加载com.zyy.process.bo.Project是无法加载的，还没有class--JAR包中可以。
        methodDefinition.setParamClazz(loadClass("com.zyy.process.bo.EntityBO"));
        methodDefinition.setResultClazz(loadClass("com.zyy.process.bo.EntityBO"));
        JoMapProcessor.sPrintMsg("paramClazz",methodDefinition.getParamClazz().toString());
        JoMapProcessor.sPrintMsg("resultClazz",methodDefinition.getResultClazz().toString());
        methodList.add(methodDefinition);
        clazzDefinition.setMethodList(methodList);
        clazzDefinition.setImportClazzSet(importSet);
        File file = new File(JoMapProcessor.javaDirAbsPath);
        if(!file.exists()){
            file.mkdirs();
        }
        build(clazzDefinition);
    }

    public static void build(ClazzDefinition clazzDefinition){
        JoMapProcessor.sPrintMsg("generate class name",clazzDefinition.getClazzName());
        JoMapProcessor.sPrintMsg("generate method list",clazzDefinition.getMethodList().toString());
        String fileAbsPath=JoMapProcessor.javaDirAbsPath+ Constant.SLASH+clazzDefinition.getClazzName()+Constant.DOT+Constant.JAVA_FILE_EXT_NAME;
        JoMapProcessor.sPrintMsg("generate java file path",fileAbsPath);
        StringBuffer buffer=new StringBuffer();
        buffer.append("package "+JoMapProcessor.joMapPackagePath+";");
        buffer.append("\r\n");
        buffer.append("\r\n");
        if(clazzDefinition.getImportClazzSet()!=null){
            for(String importClazz: clazzDefinition.getImportClazzSet()){
                buffer.append("import "+importClazz+";");
                buffer.append("\r\n");
            }
            buffer.append("\r\n");
            buffer.append("public class "+clazzDefinition.getClazzName()+" {");
            buffer.append("\r\n");
            buildMethod(buffer,clazzDefinition.getMethodList());
            buffer.append("\r\n");
            buffer.append("}");
        }
        //compiler(file.getAbsolutePath());
        //compilerFile(file.getAbsolutePath(), JoMapProcessor.targetClassDirPath);
    }

    public void generateJavaFileAndClass(){
        String code="package com.zyy.yjomapdemo.convert;\n" +
                "\n" +
                "import com.zyy.jomap.JoMapBase;\n" +
                "import com.zyy.yjomapdemo.bo.Project;\n" +
                "import com.zyy.yjomapdemo.bo.ProjectBO;\n" +
                "\n" +
                "/**\n" +
                " * @author zhangyy\n" +
                " */\n" +
                "public class ProjectConvertImpl implements JoMapBase<Project, ProjectBO> {\n" +
                "\n" +
                "    @Override\n" +
                "    public Project copyBean(ProjectBO obj) {\n" +
                "        Project project=new Project();\n" +
                "        project.setId(obj.getId());\n" +
                "        project.setName(obj.getName());\n" +
                "        System.out.println(\"id:\"+project.getId());\n" +
                "        System.out.println(\"name:\"+project.getName());\n" +
                "        return project;\n" +
                "    }\n" +
                "\n" +
                "    @Override\n" +
                "    public ProjectBO copyBeanReverse(Project obj) {\n" +
                "        ProjectBO projectConvert=new ProjectBO();\n" +
                "        projectConvert.setId(obj.getId());\n" +
                "        projectConvert.setName(obj.getName());\n" +
                "        return projectConvert;\n" +
                "    }\n" +
                "}\n";
        try {
            //在对应的项目target/generated-sources/annotations下生成JAVA原文件和在target/classes/包生成class字节码文件，可以使用loadClass来加载运行
            //无须自己再生成java文件和class字节码文件--不然重复存在
            //name为JAVA文件生成的路径(要含类名)
            JavaFileObject source = JoMapProcessor.processingEnvironment.getFiler().createSourceFile(
                    "com.zyy.jomap.convert.ProjectConvertImpl");

            Writer writer = source.openWriter();
            writer.write(code);
            writer.flush();
            writer.close();
            JoMapProcessor.sPrintMsg("javaFileObject","JavaFileObject.Kind.HTML.name()");
        } catch (IOException e) {
            //
        }
    }


    /**
     * 生成 类的方法
     * @param methodList
     */
    private static void buildMethod(StringBuffer buffer,List<MethodDefinition> methodList){
        int tabNum=1;
        String tab=generateTab(tabNum);
        for(MethodDefinition method:methodList){
            JoMapProcessor.sPrintMsg("method resultClass",method.getResultClazz().toString());
            JoMapProcessor.sPrintMsg("method paramClass",method.getParamClazz().toString());
            tab=generateTab(tabNum);
            String resultClazzName=method.getResultClazz().getSimpleName();
            String paramClazzName=method.getParamClazz().getSimpleName();
            String beanName= StringUtil.firstCharToLower(resultClazzName);
            String paramName=StringUtil.firstCharToLower(paramClazzName)+"Param";
            buffer.append(tab+"public "+ resultClazzName+" to"+resultClazzName+" ("+paramClazzName+" "+paramName+") {");
            buffer.append("\r\n");
            Class paramClazz=method.getParamClazz();
            Class returnClazz=method.getResultClazz();
            Field[] returnFieldArr=returnClazz.getDeclaredFields();
            tabNum++;
            tab=generateTab(tabNum);
            buffer.append(tab+resultClazzName+" "+beanName+" =new "+resultClazzName+"();");
            buffer.append("\r\n");
            for(Field returnField:returnFieldArr){
                String fieldName=StringUtil.firstCharToUp(returnField.getName());
                buffer.append(tab+beanName+Constant.DOT+"set"+fieldName+"("+paramName+Constant.DOT+"get"+fieldName+"());");
                buffer.append("\r\n");
            }
            buffer.append(tab+"return "+beanName+";");
            buffer.append("\r\n");
            tabNum=1;
            buffer.append(generateTab(tabNum)+"}");
            buffer.append("\r\n");
        }
    }

    private static String generateTab(int tabNum){
        String tab="";
        for(int i=0;i<tabNum;i++){
            tab+=TAB;
        }
        return tab;
    }

    /**
     * 类加载
     * @param clazzPath
     * @return
     */
    private static Class loadClass(String clazzPath){
        //类加载器
        ClassLoader classLoader=JoMapProcessor.class.getClassLoader();
        try {
            //可以加载项目中其他JAR包中的文件--"com.zyy.sdk.entity.TestEntity"
            Class entityClazz= classLoader.loadClass(clazzPath);
            JoMapProcessor.sPrintMsg("entity class name",entityClazz.getName());
            return entityClazz;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

}
